#include <stdio.h>

#include "utils.h"
#include "gobang.h"
#include "chessboard_display_handler.h"

const char *chess_character_table[3] = {
    [ChessSideToTableIndex(kCHESS_SIDE_BLACK)] = black_chess_character, 
    [ChessSideToTableIndex(kCHESS_SIDE_EMPTY)] = empty_chess_character, 
    [ChessSideToTableIndex(kCHESS_SIDE_WHITE)] = white_chess_character
};


static void printOneLineOfChessBoardMarkers(char *left, char *mid, char *right)
{
    int j;

    printf("  %s", left);
    for (j = 2; j < kBOARD_BOUND_DOWN; j++) {
        printf("   %s", mid);
    }
    printf("   %s\n", right);
}


#define print_one_line_of(x) printOneLineOfChessBoardMarkers(left_of_ ## x, mid_of_ ## x, right_of_ ## x)


static void printTopBorderOfChessBoard()
{
    print_one_line_of(top_border);
}


static void printBottomBorderOfChessBoard()
{
    print_one_line_of(bottom_border);
}


static void printSplitLineOfChessBoard()
{
    print_one_line_of(split_line);
}


static void printNumberMark(int mark)
{
    printf("%2d", mark);
}


static void printLetterMarkAtTheBottom()
{
    int j;

    printf("  ");
    for (j = 1; j < kBOARD_BOUND_RIGHT; j++) {
        printf("  %c ", 'a' + j - 1);
    }
    putchar('\n');
}


static void printOneRowOfChesses(ChessBoard *chess_board, const int row)
{
    int j;
    char chess;
    BoardCoordinates board_coord = {.x = row};

    for (j = 1; j < kBOARD_BOUND_RIGHT; j++) {
        board_coord.y = j;

        chess = Gobang_GetChessByBoardCoordinates(chess_board, board_coord);
        printf("  %s ", chess_character_table[ChessSideToTableIndex(chess)]);
    }
    putchar('\n');
}


static void printAllChessesOnBoardExceptLastRow(ChessBoard *chess_board)
{
    int i;

    for (i = 1; i < kBOARD_BOUND_DOWN - 1; i++) {
        printNumberMark(i);
        printOneRowOfChesses(chess_board, i);
        printSplitLineOfChessBoard();
    }
}


static void printLastRowOfChesses(ChessBoard *chess_board)
{
    const int last_row_number = kBOARD_BOUND_DOWN - 1;

    printNumberMark(last_row_number);
    printOneRowOfChesses(chess_board, last_row_number);
}


static void printChessesOnBoard(ChessBoard *chess_board)
{
    printAllChessesOnBoardExceptLastRow(chess_board);
    printLastRowOfChesses(chess_board);
}


void ChessBoardDisplayHandler_DisplayChessBoard(ChessBoard *chess_board)
{
    printTopBorderOfChessBoard();
    printChessesOnBoard(chess_board);
    printBottomBorderOfChessBoard();
    printLetterMarkAtTheBottom();
}